﻿using System.Diagnostics;
using System.Security.Claims;
using K9Nano.Domain.Entities;
using K9Nano.Domain.Logging;
using K9Nano.Logging;
using K9Nano.Serialization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.DependencyInjection;

namespace K9Nano.AspNetCore.Filters;

public class LoggingMiddleware
{
    private readonly RequestDelegate _next;

    public LoggingMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var sw = new Stopwatch();
        sw.Start();
        await _next(context);
        sw.Stop();

        if (context.Items[ApiLoggingWrapper.Name] is ApiLoggingWrapper loggingWrapper)
        {
            long.TryParse(context.User?.Claims.Where(a => a.Type == ClaimTypes.Sid).Select(a => a.Value).FirstOrDefault(), out var userId);

            var log = new ApiLogEntity
            {
                HttpMethod = context.Request.Method,
                Url = context.Request.GetDisplayUrl(),
                Duration = sw.ElapsedMilliseconds,
                StatusCode = context.Response.StatusCode,
                UserId = userId,
                ClientIp = GetClientIP(context),
                UserAgent = context.Request.Headers.UserAgent,
                DisplayName = loggingWrapper.DisplayName,
                CreatedAt = DateTime.Now,
                ControllerName = loggingWrapper.ControllerName,
                ActionName = loggingWrapper.ActionName,
                Arguments = loggingWrapper.Arguments == null ? null : JsonHelper.Serialize(loggingWrapper.Arguments),
                Result = loggingWrapper.Result == null ? null : JsonHelper.Serialize(loggingWrapper.Result)
            };
            var manager = context.RequestServices.GetRequiredService<IApiLogManager>();
            manager.Emit(log);
        }
    }

    public static string? GetClientIP(HttpContext context)
    {
        var ip = context.Request.Headers["Cdn-Src-Ip"].FirstOrDefault();
        if (!string.IsNullOrEmpty(ip)) return ip;

        ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
        if (!string.IsNullOrEmpty(ip)) return ip;

        return context.Connection.RemoteIpAddress?.ToString();
    }
}
